import functools
import enthought.traits.trait_types as traits
import enthought.traits.api as traits_api
import enthought.traits.ui.api as traits_ui
import enthought.traits.ui.table_filter as table_filter
from schema_ext import *

class ToTraitConversor(object):
    CORRESPONDENCE = {
    #    Object: traits.Object,
        Array: traits.List,
        Str: traits.Unicode,
        Bool: traits.Bool,
    #    Null: traits.Null,
        Int: traits.Int,
        Real: traits.Float,
    #    Number: traits.Number,
        JSONDate: traits.Date,
        JSONTime: traits.Time,
    #    JSONDateTime: traits.DateTime,
    }

    ATTR_CORRESPONDENCE = {
        'desc': 'desc',
        'label': 'label',
    }

    def __init__(self, schema, name=None):
        # Define trait's class name
        if name is None:
            name = schema.name
        if not name:
            raise ValueError('empty name.')
        self.name = name

        # Obtain information from schema
        self.schema = schema
        self.trait_attrs = {}
        for k, v in self.schema.items():
            vname = type(v).__name__
            try:
                conversor = getattr(self, 'convert_' + vname)
            except AttributeError:
                trait_t = self.CORRESPONDENCE[type(v)]
                conversor = functools.partial(self.convert_generic, trait_t=trait_t)
            self.trait_attrs[k] = conversor(v)

    def convert_generic(self, obj, trait_t):
        kwds = dict((k, getattr(obj, v)) for (k, v) in self.ATTR_CORRESPONDENCE.items())
        kwds.update((k[7:], getattr(obj.root, k)) for k in dir(obj.root) if k.startswith('traits_'))
        trait_t = trait_t(obj.default_or_null, **kwds)
        return trait_t

    def convertSomeType(self, validator):
        pass

    def trait_class(self):
        try:
            return self._trait_class
        except AttributeError:
            attrs = {'traits_view': traits_ui.View(*self.schema._fields,
                                                   buttons=['Cancel', 'OK'])}
            attrs.update(self.trait_attrs)
            self._trait_class = type(self.name, (traits_api.HasTraits,), attrs)
            return self._trait_class

    def trait_table(self):
        '''
        Trait tables are broken! do not use them,
        '''
        try:
            return self._trait_list
        except AttributeError:
            # Import trait class
            cls = self.trait_class()

            # Create custom table editor
            fields = self.schema._fields
            table_editor = \
                traits_ui.TableEditor(
                    columns=[ traits_ui.ObjectColumn(name=f) for f in fields ],
                    deletable=True,
                    editable=True,
                    auto_add=True,
                    orientation='vertical',
                    filters=[
                        table_filter.EvalFilterTemplate,
                        table_filter.MenuFilterTemplate,
                        table_filter.RuleFilterTemplate
                    ],
                    search=traits_ui.RuleTableFilter(),
                    row_factory=cls
                )

            class ListEditor(traits_api.HasStrictTraits):
                objects = traits.List(cls)

                # View object
                traits_view = \
                    traits_ui.View(
                        traits_ui.Group(
                            traits_ui.Item(
                                'objects',
                                editor=table_editor,
                                resizable=True
                            ),
                            show_border=True,
                            show_labels=False
                        ),
                        width=.4,
                        height=.4,
                        resizable=True,
                        buttons=[ 'Cancel', 'OK' ],
                        kind='live'
                    )

            self._trait_list = ListEditor
            return self._trait_list

if __name__ == '__main__':
    sch = Object({'hello': Str('world!'), 'answer': Int(42), 'bubu': Str('conossor')})
    tc = ToTraitConversor(sch, 'foo')
    t = tc.trait_class()
    tl = tc.trait_table()
    ex = tl()
    #ex.objects.append(t())
    ex.configure_traits()
    print ex.hello, ex.answer

    import doctest
    doctest.testmod(optionflags=doctest.REPORT_ONLY_FIRST_FAILURE, verbose=0)
